package cn.tedu.charging.device.repository.impl;

import cn.tedu.charging.common.constant.CacheKeyConst;
import cn.tedu.charging.common.pojo.bo.StationInfoBO;
import cn.tedu.charging.common.pojo.po.ChargingGunInfoPO;
import cn.tedu.charging.common.pojo.po.ChargingStationPO;
import cn.tedu.charging.common.pojo.query.NearStationsQuery;
import cn.tedu.charging.device.cache.StationsWamrUp;
import cn.tedu.charging.device.mapper.GunMapper;
import cn.tedu.charging.device.mapper.StationMapper;
import cn.tedu.charging.device.po.StationCanalPO;
import cn.tedu.charging.device.repository.DeviceRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;

@Repository
@Slf4j
public class DeviceRepositoryImpl implements DeviceRepository {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private GunMapper gunMapper;
    //bo的查询 不是所有属性都能从geo获取的,有一部分可以考虑读取数据库
    @Override
    public List<StationInfoBO> nearStations(NearStationsQuery query) {
        //1.利用redis的api读取命中数据 List<GeoResult>
        GeoOperations<String,Integer> geoOps = redisTemplate.opsForGeo();
        //1.1 封装circle 距离 m
        Circle circle=new Circle(query.getLongitude(),query.getLatitude(),query.getRadius());
        //1.2 查询选项 withDist withCoord
        RedisGeoCommands.GeoRadiusCommandArgs args=RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates();
        List<GeoResult<RedisGeoCommands.GeoLocation<Integer>>> geoResults = geoOps.radius(StationsWamrUp.GEO_STATIONS, circle, args).getContent();
        //2.使用geoResults,映射封装stationInfoBo,
        List<StationInfoBO> bos=null;
        if (geoResults!=null&&geoResults.size()>0){
            //非空映射
            bos=geoResults.stream().map(geoResult->{
                StationInfoBO bo=new StationInfoBO();
                //8996.7 前2位 转化千米
                Double distance=new BigDecimal(geoResult.getDistance().getValue()+"").divide(new BigDecimal("1000")).setScale(2, RoundingMode.HALF_UP).doubleValue();
                //地理位置
                BigDecimal lng=new BigDecimal(geoResult.getContent().getPoint().getX());
                BigDecimal lat=new BigDecimal(geoResult.getContent().getPoint().getY());
                //元素只
                Integer stationId=geoResult.getContent().getName();
                //单独查询 select * from charging_station where id=?
                /*ChargingStationPO stationPO = stationMapper.selectById(stationId);*/
                ChargingStationPO stationPO = getStationById(stationId);
                bo.setStationId(stationId);
                bo.setStationLat(lat);
                bo.setStationLng(lng);
                bo.setStationName(stationPO.getStationName());
                bo.setDistance(distance);
                bo.setStationStatus(stationPO.getStationStatus());
                return bo;
            }).collect(Collectors.toList());
        }
        return bos;
    }

    @Override
    public String getStationName(Integer stationId) {
        //TODO
        return "";
    }

    @Override
    public ChargingStationPO getStationById(Integer stationId) {
        //使用id查询场站信息详情 引入缓存机制
        //1.读取缓存
        String stationKey="charging:station:detail:"+stationId;
        //1.1 获取一个客户端子对象
        ValueOperations<String,ChargingStationPO> stringOps = redisTemplate.opsForValue();
        ChargingStationPO po = stringOps.get(stationKey);
        //判断po是否为空
        if(po==null){
            //2.读取数据库
            po=stationMapper.selectById(stationId);
            //3.回填缓存 让下次请求可以命中直接使用
            stringOps.set(stationKey,po);
        }
        return po;
    }

    @Override
    public List<ChargingGunInfoPO> getGunListByStationId(Integer stationId) {

        return gunMapper.selectByStationId(stationId);
    }

    @Override
    public Boolean updateGunStatus(Integer gunId, Integer status, List<Integer> integers) {
        //TODO
        return null;
    }

    @Override
    public void canalInsert(StationCanalPO stationCanalPO) {
        //1.geo需要geoadd 新增元素到集合中
        Integer stationId=stationCanalPO.getId();
        Double lng=stationCanalPO.getStationLng().doubleValue();
        Double lat=stationCanalPO.getStationLat().doubleValue();
        redisTemplate.opsForGeo().add(CacheKeyConst.GEO_STATIONS_KEY,new Point(lng,lat),stationId);
        //2.string需要set
        String cacheKey="charging:station:detail:"+stationId;
        //value值需要使用stationCanalPO转化一下ChargingStationPO
        ChargingStationPO cachePo=new ChargingStationPO();
        BeanUtils.copyProperties(stationCanalPO,cachePo);
        redisTemplate.opsForValue().set(cacheKey,cachePo);
    }

    @Override
    public void canalDelete(StationCanalPO stationCanalPO) {
        //1.geo删除元素 zrem key member
        redisTemplate.opsForGeo().remove(CacheKeyConst.GEO_STATIONS_KEY,stationCanalPO.getId());
        //2.string也要删除
        String cacheKey="charging:station:detail:"+stationCanalPO.getId();
        redisTemplate.delete(cacheKey);
    }

    @Override
    public void canalUpdate(StationCanalPO before, StationCanalPO after) {
        //对原string类型的缓存数据 做覆盖
        String cacheKey="charging:station:detail:"+after.getId();
        //使用canalPO转化成chargingStationPO
        ChargingStationPO poCache=new ChargingStationPO();
        BeanUtils.copyProperties(after,poCache);
        //覆盖原有缓存值
        redisTemplate.opsForValue().set(cacheKey,poCache);
    }
}
